package utils

import (
	"sync"
	"time"
)

type CacheFunc = func(key string, data interface{})

type cacheRec struct {
	key        string
	data       interface{}
	expiretime time.Time
	releasefun CacheFunc
}

type Cache struct {
	lock          *sync.RWMutex
	checkInterval time.Duration
	cacheMap      map[string]*cacheRec
}

func NewCache(checkInterval time.Duration) *Cache {
	rval := &Cache{
		cacheMap:      make(map[string]*cacheRec),
		checkInterval: checkInterval,
		lock:          new(sync.RWMutex),
	}
	rval.check()
	return rval
}

func (this *Cache) GetCacheCount() int {
	this.lock.RLock()
	defer this.lock.RUnlock()
	return len(this.cacheMap)

}

func (this *Cache) checkOnce() {

	this.lock.RLock()
	del_keys := make([]string, 0, len(this.cacheMap))
	for k, v := range this.cacheMap {
		if v.expiretime.Before(time.Now()) {
			del_keys = append(del_keys, k)
		}
	}
	this.lock.RUnlock()

	if len(del_keys) > 0 {
		this.lock.Lock()
		for _, key := range del_keys {
			v := this.cacheMap[key]
			if v != nil {
				if v.expiretime.Before(time.Now()) {
					if v.releasefun != nil {
						v.releasefun(v.key, v.data)
					}
					delete(this.cacheMap, key)
				}
			}
		}
		this.lock.Unlock()
	}
}

func (this *Cache) check() {
	GoFunc2(func() {
		for {
			time.Sleep(this.checkInterval)
			this.checkOnce()
		}
	})
}

func (this *Cache) GetCache(key string) interface{} {
	this.lock.RLock()
	defer this.lock.RUnlock()
	rec := this.cacheMap[key]
	if rec != nil && rec.expiretime.After(time.Now()) {
		return rec.data
	} else {
		return nil
	}
}

func (this *Cache) PutCache(key string, data interface{}, expiretime time.Duration, releasecb CacheFunc) {
	this.lock.Lock()
	defer this.lock.Unlock()
	rec := this.cacheMap[key]
	if rec != nil {
		if rec.releasefun != nil {
			rec.releasefun(rec.key, rec.data)
		}
		rec.data = data
		rec.releasefun = releasecb
		rec.expiretime = time.Now().Add(expiretime)
	} else {
		rec := &cacheRec{
			key:        key,
			data:       data,
			releasefun: releasecb,
			expiretime: time.Now().Add(expiretime),
		}
		this.cacheMap[key] = rec
	}
}
